package de.uhlesoluschns.opensearch.provider;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;

import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.LiveFolders;
import android.text.TextUtils;
import de.uhlesoluschns.opensearch.OpenSearch;
import de.uhlesoluschns.opensearch.R;
import de.uhlesoluschns.opensearch.OpenSearch.Provider;
import de.uhlesoluschns.opensearch.OpenSearch.ProviderIcon;
import de.uhlesoluschns.opensearch.OpenSearch.ProviderLiveFolder;
import de.uhlesoluschns.opensearch.OpenSearch.Suggestion;

public class OpenSearchProvider extends ContentProvider {
	
	private static final UriMatcher matcher;
	private static final Map<String, String> ENGINE_LIVE_FOLDER_PROJECTION_MAP;
	private static final int SEARCH_ENGINE_DIR = 0;
	private static final int SEARCH_ENGINE_ITEM = 1;
	private static final int SEARCH_ENGINE_LIVE = 3;

	private static final int SEARCH_SUGGESTION = 10;
	
	//Quick Search Box
	private static final int QSB_SUGGEST = 21;
	private static final int QSB_SHORTCUT = 22;
	
	private static final int HTTP_TIMEOUT_MS = 1000;
	private static final String HTTP_TIMEOUT = "http.connection-manager.timeout";
	
	 private static final String[] QSB_COLUMNS = {
		 "_id",  // must include this column
		 SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID,
		 SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
		 SearchManager.SUGGEST_COLUMN_TEXT_1,
		 SearchManager.SUGGEST_COLUMN_TEXT_2,
		 SearchManager.SUGGEST_COLUMN_ICON_1,
		 SearchManager.SUGGEST_COLUMN_QUERY,
		 SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA
	 };
	
	static {
		matcher = new UriMatcher(UriMatcher.NO_MATCH);
		matcher.addURI(OpenSearch.AUTHORITY, Provider.PATH, SEARCH_ENGINE_DIR);
		matcher.addURI(OpenSearch.AUTHORITY, Provider.PATH + "/#", SEARCH_ENGINE_ITEM);
		matcher.addURI(OpenSearch.AUTHORITY, ProviderLiveFolder.PATH, SEARCH_ENGINE_LIVE);
		matcher.addURI(OpenSearch.AUTHORITY, Suggestion.PATH + "/*", SEARCH_SUGGESTION);
		
		matcher.addURI(OpenSearch.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, QSB_SUGGEST);
		matcher.addURI(OpenSearch.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", QSB_SUGGEST);
		matcher.addURI(OpenSearch.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, QSB_SHORTCUT);
		matcher.addURI(OpenSearch.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", QSB_SHORTCUT);
		
		ENGINE_LIVE_FOLDER_PROJECTION_MAP = new HashMap<String, String>();
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, ProviderLiveFolder.COL_ID);
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, ProviderLiveFolder.COL_SHORT_NAME);
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, ProviderLiveFolder.COL_DESCRIPTION);
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.ICON_BITMAP, ProviderLiveFolder.COL_IMAGE);
	}
	
	private DatabaseHelper db;
	private HttpClient httpClient;
	
	@Override
	public boolean onCreate() {
		db = new DatabaseHelper(getContext());
		httpClient = new DefaultHttpClient();
		httpClient.getParams().setLongParameter(HTTP_TIMEOUT, HTTP_TIMEOUT_MS);
		return true;
	}
	
	@Override
	public String getType(Uri uri) {
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
		case SEARCH_ENGINE_LIVE:
			return Provider.CONTENT_DIR;
		case SEARCH_ENGINE_ITEM:
			return Provider.CONTENT_ITEM;
		case SEARCH_SUGGESTION:
			return Suggestion.CONTENT_DIR;
		case QSB_SUGGEST:
			return SearchManager.SUGGEST_MIME_TYPE;
		case QSB_SHORTCUT:
			return SearchManager.SHORTCUT_MIME_TYPE;
		default:
			System.out.println("OpenSearchProvider.getType()");
			System.out.println(uri);
		}
		return null; //"application/opensearchdescription+xml";
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
			if(selection != null) {
				return db.getWritableDatabase().delete(Provider.TABLE_NAME, selection, selectionArgs);
			}
			break;
		}
		return 0;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
			long ret = db.getWritableDatabase().insert(Provider.TABLE_NAME, null, values);
			db.createCombionedIcon(ret, values.getAsByteArray("image"));
			return Uri.withAppendedPath(uri, "" + ret);
		}
		return null;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		String query = null;
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
			return db.getReadableDatabase().query(Provider.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
		case SEARCH_ENGINE_ITEM:
			return db.getReadableDatabase().query(Provider.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
		case SEARCH_ENGINE_LIVE:
			SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
			qb.setTables(Provider.TABLE_NAME);
			qb.setProjectionMap(ENGINE_LIVE_FOLDER_PROJECTION_MAP);
			Cursor cursor = qb.query(db.getReadableDatabase(), projection, null, null, null, null, Provider.COL_SHORT_NAME);
			cursor.setNotificationUri(getContext().getContentResolver(), uri);
			return cursor; 
		case SEARCH_SUGGESTION:
			try {
				return getSuggestion(uri, selection);
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		case QSB_SUGGEST:
			 if (uri.getPathSegments().size() > 1) {
                 query = uri.getLastPathSegment();
             }
			return getQsbSuggestion(query, null, null);
		case QSB_SHORTCUT:
			System.out.println(uri);
			String id = "-1";
			 if (uri.getPathSegments().size() > 1) {
                id = uri.getLastPathSegment();
            }
			return getQsbSuggestion(query, "_id=?", new String [] {id});
		default:
			System.out.println("OpenSearchProvider.query()");
			System.out.println(uri);
			throw new IllegalStateException("Unknown URI: " + uri);
		}
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	private Cursor getSuggestion(Uri uri, String query) throws UnsupportedEncodingException {
		if(TextUtils.isEmpty(query))
			return null;
		int engineId = Integer.parseInt(uri.getLastPathSegment());
		//TODO cache
		boolean useOpenSearchProvider = false;
		if(engineId < Integer.MIN_VALUE / 2) {
			useOpenSearchProvider = true;
			engineId += Integer.MIN_VALUE;
		}
		
		Cursor engine = db.getReadableDatabase().query(Provider.TABLE_NAME, 
				new String [] {Provider.COL_INPUT_ENCODING, Provider.COL_SUGGESTION_URL, Provider.COL_SEARCH_URL}, 
				"_id=?", new String [] {"" + engineId}, null, null, null);

		if(engine.moveToFirst()) {
			String url;
			if(useOpenSearchProvider) {
				query = URLEncoder.encode(query, OpenSearch.OPEN_SEARCH_SUGGESTION_ENCODING);
				String searchUrl = URLEncoder.encode(engine.getString(2), OpenSearch.OPEN_SEARCH_SUGGESTION_ENCODING);
				System.out.println(searchUrl);
				url = String.format(OpenSearch.OPEN_SEARCH_SUGGESTION_URL_GET, query, searchUrl);
			} else {
				query = URLEncoder.encode(query, engine.getString(0));
				url = String.format(engine.getString(1), query);
			}
			engine.close();
			JSONArray ret = getJSONSuggestions(url);
			if(ret != null) {
				return new SuggestionsCursor(ret);
			}
		}
		return null;
	}
	
	public JSONArray getJSONSuggestions(String url) {
		HttpGet method = new HttpGet(url);
		HttpResponse response;
		try {
			response = httpClient.execute(method);
			if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				return new JSONArray(EntityUtils.toString(response.getEntity())).getJSONArray(1);
			}
		} catch(Exception e) {}
		return null;
	}

	private Cursor getQsbSuggestion(String query, String selection, String [] selectionArgs) {
		MatrixCursor cursor = new MatrixCursor(QSB_COLUMNS);
		Cursor engines = db.getReadableDatabase().query(Provider.TABLE_NAME, 
				new String [] {Provider.COL_ID, Provider.COL_SHORT_NAME, Provider.COL_INPUT_ENCODING, Provider.COL_SUGGESTION_URL}, 
				selection, selectionArgs, null, null, null);
		
		String noSuggestions = getContext().getResources().getString(R.string.qsb_no_suggestions);
		
		while(engines.moveToNext()) {
			int id = engines.getInt(0);
			Object suggestions = noSuggestions;
			JSONArray suggestionArray = null;
			if(!engines.isNull(3)) {
				try {
					String url = String.format(engines.getString(3), URLEncoder.encode(query, engines.getString(2)));
					suggestionArray = getJSONSuggestions(url);
					StringBuilder sb = new StringBuilder();
					int len = suggestionArray.length();
					for(int i=0; i<len; i++) {
						try {
							sb.append(suggestionArray.getString(i));
							if(i < len-1) {
								sb.append(", ");
							}
						} catch (JSONException e) {}
					}
					suggestions = sb;
				} catch (Exception e) {}
			}
			cursor.addRow(new Object[] {
				id,							//_id for cursor
				id,							//_id for SearchBox
				SearchManager.SUGGEST_NEVER_MAKE_SHORTCUT,	//shortcuts
				engines.getString(1),		//shortName
				suggestions,				//suggestions
				Uri.fromFile(getContext().getFileStreamPath(ProviderIcon.getPath(id))),	//icon
				query,						//query
				suggestionArray				//extra data
			});
		}
		
		engines.close();
		return cursor;
	}
	
}
